﻿using System;
using System.Collections.Generic;
using System.Text;
using Lon.IO.Ports;
using System.IO;

namespace Lon.IO
{
    public class SampleDev : IPeriodRun
    {
        private int devNo;

        public int DevNo
        {
            get { return devNo; }
        }

        List<CardBase> cards = new List<CardBase>();

        public List<CardBase> Cards
        {
            get { return cards; }
            set { cards = value; }
        }
        Dictionary<int,CardBase> cardDict = new Dictionary<int,CardBase>();
        List<AnalogValue> analogValues = new List<AnalogValue>();
        List<DigitValue> digitValues = new List<DigitValue>();

        private ICanDev canPort;

        public ICanDev CanPort
        {
            get { return canPort; }
            set { canPort = value; }
        }
        
        #region IPeriodRun 成员

        public void Run(ref DateTime startRunTime)
        {
            if(this.canPort==null)
            {
                return;
            }
           
            SendAnalog();
            SendDigit();

           
        }
        #endregion

        private void SendDigit()
        {
            byte[] digitBytes = this.GetDigitBytes();
            SendCanFrame(0x03, digitBytes);
        }

        private byte[] GetDigitBytes()
        {
            int bytesCount=(int)Math.Ceiling(((double)digitValues.Count)/8);
            byte[] res = new byte[bytesCount];
            MemoryStream ms = new MemoryStream(res);
            BinaryWriter bw = new BinaryWriter(ms);
            for(int i=0;i<bytesCount;i++)
            {
                byte val = 0;
                for(int j=0;j<8;j++)
                {
                    int digitIndex = i * 8 + j;
                    if (digitIndex >= this.digitValues.Count)
                    {
                        break;
                    }
                    val += (byte)(this.digitValues[i * 8 + j].Val<<j);
                 
                }
                bw.Write(val);
            }
            return res;
        }

        private void SendAnalog()
        {
            byte[] analogBytes = this.GetAnalogBytes();
            if (analogBytes.Length == 0)
            {
                return;
            }
            SendCanFrame(0x04, analogBytes);

        }

        private void SendCanFrame(int frameType, byte[] bytes)
        {
           int frameCount=(int)Math.Ceiling(((double)bytes.Length)/6.0);
           for (int i = 0; i < frameCount; i++)
           {
               byte frameEndFlag = 0x20;
               if(i==0)
               {
                   frameEndFlag = 0x10;
               }
               if(i==frameCount-1)
               {
                   frameEndFlag = 0x30;
               }
               CanFrame cf = new CanFrame();
               cf.CanId = this.devNo << 3;
               cf.CanId += frameType;
               int sendDataLength=(bytes.Length-i*6)+2;
               if(sendDataLength>8)
               {
                   sendDataLength=8;
               }

               cf.Buf = new byte[sendDataLength];
               cf.Buf[0] = frameEndFlag;
               cf.Buf[1] = (byte)i;
               Array.Copy(bytes, i * 6, cf.Buf, 2, sendDataLength - 2);
               this.canPort.WriteCanFrame(cf);
           }
        }


        internal void InitFromParam(SampleDevParam10 param)
        {
            this.devNo = param.DevNo;
            for (int i = 0; i < param.CardItems.Count; i++)
            {
                SampleDevCardParam10 cardParam = param.CardItems[i];
                CardBase card = CreateCard(cardParam);
                if (card == null)
                {
                    continue;
                }
                card.InitForm(cardParam);
                this.digitValues.AddRange(card.DigitValues);
                this.analogValues.AddRange(card.AnalogValues);
                this.cards.Add(card);
                this.cardDict.Add(card.CardNo, card);
            }
        }
      
        
        private CardBase CreateCard(SampleDevCardParam10 cardParam)
        {
            switch (cardParam.CardType)
            {
                case 1:
                    return new CardDigit(cardParam.CardNo);
                case 3:
                case 4:
                    return new CardGeneralAd(cardParam.CardNo);
                case 26:
                case 29:
                    return new SensorFskSend(cardParam.CardNo);
                case 30:
                    return new SensorFskRecv(cardParam.CardNo);
                case 16:
                     return new SensorTurnoutStateAC(cardParam.CardNo);
                case 17:
                    return new SensorTurnoutStateDC(cardParam.CardNo);
                case 18:
                    return null;             
         
                case 19:
                    return new SensorTurnoutAC(cardParam.CardNo);
                case 20:
                    return new SensorTurnoutDC(cardParam.CardNo);
                case 21:
                    return new SensorStaitonConnect(cardParam.CardNo);
                case 22:
                    return null;
                case 23:
                    return new SensorSemiAuto(cardParam.CardNo);
                case 24:
                    return new SensorStaitonConnect(cardParam.CardNo);
                case 25:
                    return null;

           

                default:
                    return null;
            }
        }

        internal byte[] GetAnalogBytes()
        {
            byte[] res = new byte[this.analogValues.Count * 2];
            MemoryStream ms = new MemoryStream(res);
            BinaryWriter br = new BinaryWriter(ms);
            for(int i=0;i<analogValues.Count;i++)
            {
                br.Write(analogValues[i].Val);
            }
            return res;
        }

        public void SetValue(int cardNum, int analogNum, Int16 val)
        {
            if (!cardDict.ContainsKey(cardNum))
            {
                return;
            }
            cardDict[cardNum].SetValue(analogNum, val);
        }

        internal void LoadDefaultAnalogVal(Section sec)
        {
            for (int i = 0; i < this.cards.Count; i++)
            {
                Int32[] vals = sec.GetIntArr(this.cards[i].CardNo.ToString(),-1);
                this.cards[i].SetDefaultVals(vals);

            }
        }

        internal void LoadDefaultKglVal(Section sec)
        {
            for (int i = 0; i < this.cards.Count; i++)
            {
                Int32[] vals = sec.GetIntArr(this.cards[i].CardNo.ToString(), -1);
                this.cards[i].SetDefaultKglVals(vals);

            }
        }

        internal void SetDigit(int cardNum, int analogNum, Int16 val)
        {
            if (!cardDict.ContainsKey(cardNum))
            {
                return;
            }
            cardDict[cardNum].SetDigit(analogNum,(byte) val);
        }
    }
}
